<template>
  <div class="custom-table-container" v-loading="loading">
    <div class="custom-table" v-infinite-scroll="loadData">
      <table cellspacing="0" cellpadding="0">
        <thead
          class="tableThead"
          :style="{ transform: `translateY(${scrollTop}px)` }"
        >
          <tr
            v-for="(displayCol, displayColIndex) in displayColumns"
            :key="displayColIndex"
          >
            <th
              v-for="(col, colIndex) in displayCol"
              :key="col.prop"
              :class="{
                headLeft: col.fixed,
                headRight: !col.fixed,
                'enable-click': col.enabledClick,
              }"
              :rowspan="col.rowspan == undefined ? 1 : col.rowspan"
              :colspan="col.colspan == undefined ? 1 : col.colspan"
              :style="
                col.fixed
                  ? {
                      width: col.headerWidth,
                      background: col.background,
                      color: col.color,
                      transform: `translateX(${scrollLeft}px)`,
                    }
                  : {
                      width: col.headerWidth,
                      background: col.background,
                      color: col.color,
                    }
              "
              @click="handleHeadCellClick(col)"
            >
              <div class="cell" :style="{ width: col.width + 'px' }">
                <span>{{ col.label }}</span>
                <el-popover
                  placement="bottom"
                  trigger="click"
                  v-if="
                    col.conditionList &&
                    col.conditionList.length &&
                    filterConditionValues[col.prop]
                  "
                >
                  <el-checkbox-group
                    v-model="filterConditionValues[col.prop]"
                    @change="handleFilter(col, $event)"
                  >
                    <el-checkbox
                      v-for="condition in col.conditionList"
                      :key="condition"
                      :label="condition"
                      :style="{
                        display: 'block',
                        'margin-right': 0,
                        'line-height': '26px',
                      }"
                    ></el-checkbox>
                  </el-checkbox-group>
                  <svg-icon
                    slot="reference"
                    icon-class="filter"
                    :class-name="`filter-icon ${
                      filterConditionValues[col.prop] &&
                      filterConditionValues[col.prop].length > 0
                        ? 'highlight'
                        : ''
                    }`"
                  />
                </el-popover>
              </div>
            </th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="(row, rowIndex) in tableData"
            :key="rowIndex"
            :class="{ active: activeRowKeys.includes(row[rowKey]) }"
            @click="handleRowClick(row, rowIndex)"
          >
            <td
              v-for="(col, colIndex) in dataColumns"
              :key="`${rowIndex}_${colIndex}`"
              :class="{
                bodyLeft: col.fixed,
                bodyRight: !col.fixed,
                'enable-click': col.enabledClick,
                intersection: col.mergeCell === true,
              }"
              :style="
                col.fixed ? { transform: `translateX(${scrollLeft}px)` } : {}
              "
              :data-code="`${rowIndex}_${colIndex}`"
              :rowspan="row[col.prop].rowspan || 1"
              v-if="row[col.prop].rowspan != 0"
              @click="handleBodyCellClick(row, col)"
            >
              <div
                :class="[
                  'cell',
                  col.cellClass ? col.cellClass(row.sourceRow, col) : '',
                  { intersection: col.mergeCell === true },
                ]"
                :data-code="`${rowIndex}_${colIndex}`"
              >
                {{
                  [undefined, null].includes(row[col.prop].value) &&
                  col.emptyValue
                    ? col.emptyValue
                    : col.formatter
                    ? col.formatter(row.sourceRow, col)
                    : row[col.prop].value
                }}
              </div>
              <template v-if="showIntersectionTip && col.mergeCell === true">
                <div
                  :class="[
                    'virtual-cell',
                    `virtual-cell-${rowIndex}_${colIndex}`,
                  ]"
                  v-if="
                    isNotIntersectingDom[`${rowIndex}_${colIndex}`] &&
                    isNotIntersectingDom[`${rowIndex}_${colIndex}`].status ==
                      'TdCellActive'
                  "
                >
                  {{
                    [undefined, null].includes(row[col.prop].value) &&
                    col.emptyValue
                      ? col.emptyValue
                      : col.formatter
                      ? col.formatter(row.sourceRow, col)
                      : row[col.prop].value
                  }}
                </div>
              </template>
            </td>
          </tr>
        </tbody>
      </table>
      <div v-if="!tableData || !tableData.length" class="no-data">暂无数据</div>
    </div>
  </div>
</template>
<script>
import { flattenTreeData } from "@/utils/tree";
import mixin from "./mixin";
export default {
  props: {
    srouceTableData: {
      type: Array,
      default: () => [],
    },
    columns: {
      type: Array,
      default: () => [],
    },
    isAutoMergeRowspan: {
      type: Boolean,
      default: true,
    },
    customFilter: {
      type: Boolean,
      default: false,
    },
    lazy: {
      type: Boolean,
      default: true,
    },
    showIntersectionTip: {
      type: Boolean,
      default: true,
    },
    singleSelect: {
      type: Boolean,
      default: false,
    },
    multiSelect: {
      type: Boolean,
      default: false,
    },
    rowKey: {
      type: String,
      default: "",
    },
  },
  mixins: [mixin],
  data() {
    return {
      displaySourceData: [],
      tableData: [],
      pager: {
        pageNum: 1,
        pageSize: 500,
      },
      loading: false,
      customTable: null,
      scrollTop: 0,
      scrollLeft: 0,
      timer: null,
      filterConditionValues: {},
      observer: null,
      isNotIntersectingDom: {},
      activeRowKeys: [],
    };
  },
  computed: {
    displayColumns() {
      const columns = this.columns;
      if (!columns?.length) {
        return [];
      }
      let result = this.flattenToLevelArr({ children: columns });

      return result.slice(1);
    },
    dataColumns() {
      return flattenTreeData(this.columns).filter(
        (ele) => !ele.children?.length
      );
    },
  },
  mounted() {},
  methods: {
    loadData() {
      const { pageNum, pageSize } = this.pager;

      if (pageSize * (pageNum - 1) >= this.displaySourceData.length) {
        return;
      }
      const moreData = this.displaySourceData.slice(0, pageSize * pageNum);

      if (this.isAutoMergeRowspan == true) {
        this.setRowSpanData(moreData, true);
      }

      this.tableData = moreData;
      this.pager.pageNum++;

      this.$nextTick(() => {
        this.initScroll();
        if (this.showIntersectionTip) {
          this.initElementIntersetion();
        }
      });
    },
    initElementIntersetion() {
      if (!window.IntersectionObserver) {
        console.warn("该浏览器不支持IntersectionObserver！");
        return;
      }
      this.clearObserver();

      const headLeft = this.$el.querySelector(".headLeft");
      const headHeight = headLeft ? headLeft.offsetHeight : 0;

      this.observer = new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              // 当元素进入容器时触发
              // console.log("元素已经进入容器", entry);

              if (entry.target.tagName == "TD") {
                if (
                  !this.isNotIntersectingDom.hasOwnProperty(
                    entry.target.dataset.code
                  )
                ) {
                  this.$set(
                    this.isNotIntersectingDom,
                    entry.target.dataset.code,
                    {
                      status: "TdCellActive",
                      dom: entry.target,
                      text: entry.target.innerText,
                      code: entry.target.dataset.code,
                    }
                  );
                }
              } else if (entry.target.tagName == "DIV") {
                if (
                  this.isNotIntersectingDom.hasOwnProperty(
                    entry.target.dataset.code
                  )
                ) {
                  this.$set(
                    this.isNotIntersectingDom,
                    entry.target.dataset.code,
                    {
                      status: "TextCellActive",
                      code: entry.target.dataset.code,
                    }
                  );
                }
              }
            } else {
              // 当元素退出容器时触发
              // console.log("元素已经退出容器", entry);

              if (entry.target.tagName == "TD") {
                delete this.isNotIntersectingDom[entry.target.dataset.code];
              } else if (entry.target.tagName == "DIV") {
                if (
                  this.isNotIntersectingDom.hasOwnProperty(
                    entry.target.dataset.code
                  )
                ) {
                  this.$set(
                    this.isNotIntersectingDom,
                    entry.target.dataset.code,
                    {
                      status: "TdCellActive",
                      dom: entry.target.parentElement,
                      text: entry.target.innerText,
                      code: entry.target.dataset.code,
                    }
                  );
                }
              }
            }
          });
        },
        {
          root: this.$el.querySelector(".custom-table"),
          rootMargin: `${-headHeight - 16}px 0px -16px 0px`,
        }
      );
      const doms = this.$el.querySelectorAll(".intersection");
      for (let index = 0; index < doms.length; index++) {
        const dom = doms[index];
        this.observer.observe(dom);
      }
    },
    initScroll() {
      const customTable = this.$el.getElementsByClassName("custom-table");
      this.customTable = customTable ? customTable[0] : null;
      if (!this.customTable) {
        return;
      }

      this.customTable.removeEventListener("scroll", this.scroll);

      this.customTable.addEventListener("scroll", this.scroll);
    },
    scroll(event) {
      // document.body.click();

      const { scrollTop, scrollLeft } = event.target;

      this.scrollTop = scrollTop;
      this.scrollLeft = scrollLeft;

      if (this.showIntersectionTip) {
        const isNotIntersectingDom = this.isNotIntersectingDom;

        for (const key in isNotIntersectingDom) {
          if (Object.hasOwnProperty.call(isNotIntersectingDom, key)) {
            const ele = isNotIntersectingDom[key];
            if (ele.status == "TdCellActive" && ele.dom) {
              const virtualDom = this.$el.querySelector(
                `.virtual-cell-${ele.code}`
              );
              if (virtualDom) {
                const Y = scrollTop - ele.dom.offsetTop;
                virtualDom.style.transform = `translateY(${Y < 0 ? 0 : Y}px)`;
              }
            }
          }
        }
      }
    },
    throttle(func, delay = 100) {
      if (!this.timer) {
        this.timer = setTimeout(() => {
          func();
          this.timer = null;
        }, delay);
      }
    },
    handleFilter(column, value) {
      if (this.customFilter == true) {
        // 自定义过滤，传入方法done，重置滚动监听
        this.$emit("filter", { column, value }, () => {
          this.resetScroll();
        });
      } else {
        // 数据筛选
        // 取出所有条件
        const _filterConditionValues = {};
        for (const key in this.filterConditionValues) {
          if (Object.hasOwnProperty.call(this.filterConditionValues, key)) {
            const element = this.filterConditionValues[key];
            if (element?.length > 0) {
              _filterConditionValues[key] = [...element];
            }
          }
        }

        const keys = Object.keys(_filterConditionValues);

        if (!keys?.length) {
          // 没有筛选条件
          this.displaySourceData = this.formatterData(this.srouceTableData);
        } else {
          // 有筛选条件
          const _displaySourceData = this.srouceTableData.filter((row) => {
            let flag = true;
            for (let i = 0; i < keys.length; i++) {
              const key = keys[i];
              if (_filterConditionValues[key].indexOf(row[key]) === -1) {
                flag = false;
              }
              if (!flag) {
                continue;
              }
            }
            return flag;
          });
          this.displaySourceData = this.formatterData(_displaySourceData);
        }

        this.tableData = [];
        this.pager.pageNum = 1;

        this.loadData();

        // 重置表格滚动监听
        this.resetScroll();
      }
    },
    handleRowClick(row, rowIndex) {
      if (this.rowKey) {
        if (this.multiSelect) {
          if (this.activeRowKeys.includes(row[this.rowKey])) {
            // 取消选中
            this.activeRowKeys = this.activeRowKeys.filter(
              (key) => key != row[this.rowKey]
            );
          } else {
            // 选中
            this.activeRowKeys = this.activeRowKeys.concat(row[this.rowKey]);
          }
          const sourceRows = this.tableData
            .filter((r) => this.activeRowKeys.includes(r[this.rowKey]))
            .map((r) => r.sourceRow);
          this.$emit("select-change", sourceRows);
        } else if (this.singleSelect) {
          if (!this.activeRowKeys.includes(row[this.rowKey])) {
            // 选中
            this.activeRowKeys = [row[this.rowKey]];
            this.$emit("select-change", [row.sourceRow]);
          }
        }
      }

      this.$emit("row-click", row.sourceRow);
    },
    handleHeadCellClick(column) {
      if (column.enabledClick) {
        this.$emit("head-cell-click", column);
      }
    },
    handleBodyCellClick(row, column) {
      if (column.enabledClick) {
        this.$emit("body-cell-click", row.sourceRow, column);
      }
    },
    //  重置表格滚动监听
    resetScroll() {
      this.$nextTick(() => {
        this.initScroll();

        if (this.customTable) {
          this.customTable.scrollTo(0, 0);
          this.scrollTop = 0;
          this.scrollLeft = 0;
        }
      });
    },
    updateFilterConditionValues(value = {}) {
      if (value) {
        const filtervalues = { ...this.filterConditionValues };
        for (const key in filtervalues) {
          if (Object.hasOwnProperty.call(filtervalues, key)) {
            filtervalues[key] = value[key] || [];
          }
        }
        this.filterConditionValues = filtervalues;

        const keys = Object.keys(this.filterConditionValues);
        if (this.customFilter != true) {
          // 数据筛选
          if (Object.keys(value).length) {
            const _displaySourceData = this.srouceTableData.filter((row) => {
              let flag = false;
              for (let i = 0; i < keys.length; i++) {
                const k = keys[i];
                if (value[k]?.includes(row[k])) {
                  flag = true;
                  continue;
                }
              }
              return flag;
            });
            this.displaySourceData = this.formatterData(_displaySourceData);
          } else {
            this.displaySourceData = this.formatterData(this.srouceTableData);
          }

          this.tableData = [];
          this.pager.pageNum = 1;

          this.loadData();

          // 重置表格滚动监听
          this.resetScroll();
        }
      }
    },
    // 设置选中行
    setActiveRow(rowkeys) {
      if (this.multiSelect) {
        this.activeRowKeys = rowkeys;
      } else if (this.singleSelect) {
        this.activeRowKeys = [rowkeys];
      }
    },
    // 清除提示
    clearObserver() {
      if (this.observer) {
        this.observer.disconnect();
        this.observer = null;
      }

      this.isNotIntersectingDom = {};
    },
  },
  activated() {
    this.resetScroll();
    if (this.showIntersectionTip) {
      this.$nextTick(() => {
        this.initElementIntersetion();
      });
    }
  },
  deactivated() {},
  watch: {
    srouceTableData: {
      handler(newVal) {
        newVal = newVal || [];
        if (this.lazy == false) {
          this.pager.pageSize = newVal.length;
        }
        this.displaySourceData = this.formatterData(newVal) || [];

        this.tableData = [];
        this.pager.pageNum = 1;
        this.loadData();

        this.$nextTick(() => {
          this.resetScroll();
        });
      },
      immediate: true,
    },
    dataColumns: {
      handler(newVal) {
        let res = {};
        newVal.forEach((ele) => {
          if (ele.conditionList?.length) {
            res[ele.prop] = this.filterConditionValues[ele.prop] || [];
          }
        });
        this.filterConditionValues = res;
      },
      immediate: true,
    },
  },
  beforeDestroy() {
    this.clearObserver();
  },
};
</script>
<style lang="scss" scoped>
@import "../../assets/styles/element-variables";
.custom-table-container {
  width: 100%;
  height: 100%;
  font-size: 15px;
}
.custom-table {
  width: 100%;
  height: 100%;
  overflow-x: auto;
  overflow-y: auto;
  border: 1px solid #e6e6e6;
  position: relative;
  table {
    min-width: 100%;
  }
  td,
  th {
    font-weight: 500;
    border-bottom: 1px solid #e6e6e6;
    background-color: #ffffff;
    &.enable-click {
      cursor: pointer;
    }
    &:not(:last-child) {
      border-right: 1px solid #e6e6e6;
    }
  }
  tr.active {
    td {
      background-color: $--color-primary;
      color: #ffffff;
    }
  }
  .tableThead {
    position: relative;
    z-index: 10;
  }
  th.headLeft {
    position: relative;
    z-index: 3;
  }
  td.bodyLeft {
    position: relative;
    z-index: 2;
  }
  td.bodyRight {
    position: relative;
    z-index: 1;
  }
  tbody {
    position: relative;
    //   td {
    //     transition: background-color 0.25s ease;
    //   }
    //   tr:hover {
    //     td {
    //       background-color: rgb(245, 247, 250);
    //     }
    //   }
  }
  .cell {
    min-width: 100%;
    min-height: 36px;
    text-align: center;
    padding: 0 8px;
    box-sizing: border-box;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    .filter-icon {
      position: absolute;
      right: 5px;
      bottom: 5px;
      font-size: 13px;
      cursor: pointer;
      outline: none;
      &.highlight {
        color: #ffa162;
      }
    }
  }
  .virtual-cell {
    position: absolute;
    top: 1px;
    left: 0;
    width: 100%;
    text-align: center;
    padding: 10px 8px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    color: #888888;
    background-color: #ffffff;
    user-select: none;
  }
}
.no-data {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #cccccc;
}
</style>
